/**
 *****************************************************************************
 * @file
 * @brief
 * @author taoye
 * @version V0.0.1
 * @date 2021/08/24
 ****************************************************************************
 */

 /* Includes ------------------------------------------------------------------*/
#include "drv_f4_usart.h"

/* Private defines -----------------------------------------------------------*/


/* Private Struct  -----------------------------------------------------------*/
typedef struct
{
    USART_TypeDef *         USARTx;
    DMA_Stream_TypeDef *    DMA_Stream;
    uint32_t                DMA_CHANNEL;
    uint8_t *               rx_data;
    uint32_t                irq;
    void ( * Idle_CallBack )( uint8_t *, uint32_t );
}usart_para_t;

struct men_pool{

    uint8_t rx_mem[USART_MEM_SIZE];
    uint32_t rx_cnt;
};

/* Private enum    -----------------------------------------------------------*/


/* Private Variable  ---------------------------------------------------------*/
static usart_para_t para[]={
    {.USARTx = USART1, .irq = USART1_IRQn, .DMA_Stream = DMA2_Stream2,  .DMA_CHANNEL = DMA_Channel_4},
    {.USARTx = USART2, .irq = USART2_IRQn, .DMA_Stream = DMA1_Stream5,  .DMA_CHANNEL = DMA_Channel_4},
    {.USARTx = USART3, .irq = USART3_IRQn, .DMA_Stream = DMA1_Stream1,  .DMA_CHANNEL = DMA_Channel_4},
    {.USARTx = UART4,  .irq = UART4_IRQn,  .DMA_Stream = DMA1_Stream2,  .DMA_CHANNEL = DMA_Channel_4},
    {.USARTx = UART5,  .irq = UART5_IRQn,  .DMA_Stream = DMA1_Stream0,  .DMA_CHANNEL = DMA_Channel_4},
    {.USARTx = USART6, .irq = USART6_IRQn, .DMA_Stream = DMA2_Stream1,  .DMA_CHANNEL = DMA_Channel_5},
};

static struct men_pool mem ={
    .rx_cnt = 0,
};

/***********************************************************************************
 * @brief 		
 * ex:
 * @par
 * None
 * @retval void None
 **********************************************************************************/
static uint8_t *Usart_Malloc(uint16_t len)
{
    uint32_t return_val;
    
    if((mem.rx_cnt + len) > USART_MEM_SIZE){
        return NULL;
    }
    
    return_val = (uint32_t)(mem.rx_mem) + mem.rx_cnt;
    mem.rx_cnt += len;
    
    return (uint8_t *)return_val;
}
/***********************************************************************************
 * @brief 		
 * ex:
 * @par
 * None
 * @retval void None
 **********************************************************************************/
static int Usart_Gpio_Init(drv_usart_t *this)
{
    uint8_t             afconfig;

    if(this->private.USARTx == USART1){
        afconfig = GPIO_AF_USART1;
    }
    else if(this->private.USARTx == USART2){
        afconfig = GPIO_AF_USART2;
    }
    else if(this->private.USARTx == USART3){
        afconfig = GPIO_AF_USART3;
    }
    else if(this->private.USARTx == UART4){
        afconfig = GPIO_AF_UART4;
    }
    else if(this->private.USARTx == UART5){
        afconfig = GPIO_AF_UART5;
    }
    else if(this->private.USARTx == USART6){
        afconfig = GPIO_AF_USART6;
    }

    //  TX IO
    if(Common_Gpio_AFConfig(this->Tx_Pin, afconfig, GPIO_PuPd_UP) < 0){
        return -1;
    }

    //  RX IO
    if(Common_Gpio_AFConfig(this->Rx_Pin, afconfig, GPIO_PuPd_NOPULL) < 0){
        return -1;
    }

    return 0;
}

/***********************************************************************************
 * @brief 		
 * ex:
 * @par
 * None
 * @retval void None
 **********************************************************************************/
static int Usart_Dma_Init(int index)
{
    DMA_InitTypeDef DMA_InitStructure;
    
    RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_DMA1, ENABLE);
    RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_DMA2, ENABLE);
    
    DMA_DeInit(para[index].DMA_Stream);
    DMA_InitStructure.DMA_Channel = para[index].DMA_CHANNEL; 
    DMA_InitStructure.DMA_PeripheralBaseAddr  = (uint32_t)(&(para[index].USARTx->DR));
    DMA_InitStructure.DMA_Memory0BaseAddr     = (uint32_t)para[index].rx_data;         
    DMA_InitStructure.DMA_DIR                 = DMA_DIR_PeripheralToMemory;
    DMA_InitStructure.DMA_BufferSize          = USART_DMA_RXBUFF_SIZE;                      
    DMA_InitStructure.DMA_PeripheralInc       = DMA_PeripheralInc_Disable;  
    DMA_InitStructure.DMA_MemoryInc           = DMA_MemoryInc_Enable;         
    DMA_InitStructure.DMA_PeripheralDataSize  = DMA_MemoryDataSize_Byte;   
    DMA_InitStructure.DMA_MemoryDataSize      = DMA_MemoryDataSize_Byte;
    DMA_InitStructure.DMA_Mode                = DMA_Mode_Normal;          
    DMA_InitStructure.DMA_Priority            = DMA_Priority_VeryHigh;      
    DMA_InitStructure.DMA_FIFOMode            = DMA_FIFOMode_Disable;       
    DMA_InitStructure.DMA_FIFOThreshold       = DMA_FIFOThreshold_Full; //DMA_FIFOThreshold_HalfFull;  
    DMA_InitStructure.DMA_MemoryBurst         = DMA_MemoryBurst_Single;     
    DMA_InitStructure.DMA_PeripheralBurst     = DMA_PeripheralBurst_Single;

    /* 3.配置DMA */
    DMA_Init(para[index].DMA_Stream, &DMA_InitStructure);

    /* 5.使能串口的DMA接收 */
    USART_DMACmd(para[index].USARTx, USART_DMAReq_Rx, ENABLE);

    /* 7.使能DMA */ 
    DMA_Cmd(para[index].DMA_Stream, ENABLE);   

    return 0;
}
/***********************************************************************************
 * @brief 		
 * ex:
 * @par
 * None
 * @retval void None
 **********************************************************************************/
static int Usart_Check_name(const char *name)
{
    uint8_t nlen = strlen(name);
    if(nlen > 6 || nlen < 5){
        return -1;
    }
    uint8_t index = name[nlen - 1] - '0';
    if(index > (sizeof(para) / sizeof(usart_private_t))){
        return -1;
    }    
    index -= 1;
    
    return index;
}
/***********************************************************************************
 * @brief 		
 * ex:
 * @par
 * None
 * @retval void None
 **********************************************************************************/
uint32_t Usart_Send(drv_usart_t *this, uint8_t *data, uint32_t len)
{
	for(uint32_t i=0; i<len; i++)
	{
		USART_SendData(this->private.USARTx, (unsigned char) data[i]);
		while (!(this->private.USARTx->SR & USART_FLAG_TXE));
	}
    
    return len;
}

// add dma send

/***********************************************************************************
 * @brief 		
 * ex:
 * @par
 * None
 * @retval void None
 **********************************************************************************/
int Drv_Usart_Init(drv_usart_t *this)
{
    int index = Usart_Check_name(this->Drv_Num);
    if(index < 0){
        return -1;
    }
    this->private.USARTx        = para[index].USARTx;
    this->Write                 = Usart_Send;
    para[index].Idle_CallBack   = this->Idle_CallBack;

    para[index].rx_data = Usart_Malloc(USART_DMA_RXBUFF_SIZE);
    if(para[index].rx_data == NULL){
        return -1;
    }
    
    switch(index)
    {
        case 0:
            RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1, ENABLE);
        break;
        case 1:
            RCC_APB1PeriphClockCmd(RCC_APB1Periph_USART2, ENABLE);
        break;
        case 2:
            RCC_APB1PeriphClockCmd(RCC_APB1Periph_USART3, ENABLE);
        break;
        case 3:
            RCC_APB1PeriphClockCmd(RCC_APB1Periph_UART4, ENABLE);
        break;
        case 4:
            RCC_APB1PeriphClockCmd(RCC_APB1Periph_UART5, ENABLE);
        break;
        case 5:
            RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART6, ENABLE);
        break;
    }

    if(Usart_Gpio_Init(this) < 0){
        return -1;
    }

    /* 设置中断并打开时钟 */
    NVIC_InitTypeDef NVIC_InitStructure;
    NVIC_InitStructure.NVIC_IRQChannel                      = para[index].irq;
    NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority    = this->Rx_Priority;      
    NVIC_InitStructure.NVIC_IRQChannelSubPriority           = this->Rx_Priority;       
    NVIC_InitStructure.NVIC_IRQChannelCmd                   = ENABLE;
    NVIC_Init(&NVIC_InitStructure);
    
    uint32_t StopBits,WordLength,Parity;
    switch(this->WordLength){
        case USART_WORDLENGTH_8BIT:
            WordLength = USART_WordLength_8b;
        break;
        case USART_WORDLENGTH_9BIT:
            WordLength = USART_WordLength_9b;
        break;
    }
    switch(this->Parity){
        case USART_PARITY_NO:
            Parity = USART_Parity_No;
        break;
        case USART_PARITY_EVEN:
            Parity = USART_Parity_Even;
        break;
        case USART_PARITY_ODD:
            Parity = USART_Parity_Odd;
        break;
    }
    switch(this->StopBits){
        case USART_STOPBITS_0_5BIT:
            StopBits = USART_StopBits_0_5;
        break;
        case USART_STOPBITS_1BIT:
            StopBits = USART_StopBits_1;
        break;
        case USART_STOPBITS_1_5BIT:
            StopBits = USART_StopBits_1_5;
        break;
        case USART_STOPBITS_2BIT:
            StopBits = USART_StopBits_2;
        break;
    }

    /* 设置串口参数 */
    USART_InitTypeDef   USART_InitStructure;
    USART_InitStructure.USART_BaudRate            = this->BaudRate;                             
    USART_InitStructure.USART_WordLength          = WordLength;                    
    USART_InitStructure.USART_StopBits            = StopBits;                           
    USART_InitStructure.USART_Parity              = Parity;
    USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None; 
    USART_InitStructure.USART_Mode                = USART_Mode_Rx | USART_Mode_Tx; 
    USART_Init(para[index].USARTx , &USART_InitStructure);
    
    /* 使能IDLE中断 */
    USART_ITConfig(para[index].USARTx , USART_IT_IDLE, ENABLE);
	
//	USART_ClearITPendingBit(para[index].USARTx, USART_IT_TC); // 清除中断TC位 
//    USART_ClearITPendingBit(para[index].USARTx, USART_IT_RXNE);
//	USART_ClearITPendingBit(para[index].USARTx, USART_IT_IDLE);
    
    /* 使能串口 */
    USART_Cmd(para[index].USARTx , ENABLE);
    
    // DMA初始化
    if(Usart_Dma_Init(index) < 0){
        return -1;
    }
    
	this->private.USARTxMutex = xSemaphoreCreateMutex();
    
	return 0;
}
/***********************************************************************************
 * @brief 		
 * ex:
 * @par
 * None
 * @retval void None
 **********************************************************************************/
static uint32_t DMA_Snum(DMA_Stream_TypeDef * DMA_Stream)
{
         if(DMA_Stream == DMA1_Stream0 || DMA_Stream == DMA2_Stream0){
        return DMA_FLAG_TCIF0;
    }
    else if(DMA_Stream == DMA1_Stream1 || DMA_Stream == DMA2_Stream1){
        return DMA_FLAG_TCIF1;
    }    
    else if(DMA_Stream == DMA1_Stream2 || DMA_Stream == DMA2_Stream2){
        return DMA_FLAG_TCIF2;
    } 
    else if(DMA_Stream == DMA1_Stream3 || DMA_Stream == DMA2_Stream3){
        return DMA_FLAG_TCIF3;
    } 
    else if(DMA_Stream == DMA1_Stream4 || DMA_Stream == DMA2_Stream4){
        return DMA_FLAG_TCIF4;
    } 
    else if(DMA_Stream == DMA1_Stream5 || DMA_Stream == DMA2_Stream5){
        return DMA_FLAG_TCIF5;
    } 
    else if(DMA_Stream == DMA1_Stream6 || DMA_Stream == DMA2_Stream6){
        return DMA_FLAG_TCIF6;
    } 
    else if(DMA_Stream == DMA1_Stream7 || DMA_Stream == DMA2_Stream7){
        return DMA_FLAG_TCIF7;
    } 
    
    return DMA_FLAG_TCIF0;
}
/***********************************************************************************
 * @brief 		
 * ex:
 * @par
 * None
 * @retval void None
 **********************************************************************************/
#define  USART_IRQHANDLER(id)                                                   \
void USART##id##_IRQHandler(void)                                               \
{                                                                               \
    usart_para_t * this = &para[id - 1];                                        \
    uint16_t len;                                                               \
                                                                                \
    if(USART_GetITStatus(USART##id, USART_IT_IDLE) != RESET)                    \
    {                                                                           \
		DMA_Cmd(this->DMA_Stream, DISABLE);                                     \
		USART##id->SR;                                                          \
        USART##id->DR;                                                          \
        DMA_ClearFlag(this->DMA_Stream, DMA_Snum(this->DMA_Stream));            \
        len = USART_DMA_RXBUFF_SIZE - DMA_GetCurrDataCounter(this->DMA_Stream); \
        this->Idle_CallBack(this->rx_data, len);                                \
        DMA_SetCurrDataCounter(this->DMA_Stream, USART_DMA_RXBUFF_SIZE);        \
        DMA_Cmd(this->DMA_Stream,ENABLE);                                       \
		USART_ClearITPendingBit(USART##id,USART_IT_IDLE);                       \
    }                                                                           \
}                                                                               \
		                 
		
//        USART##id->SR;                                                          \
//        USART##id->DR;                                                          \
//        DMA_Cmd(this->DMA_Stream, DISABLE);                                     \
//        DMA_ClearFlag(this->DMA_Stream, DMA_Snum(this->DMA_Stream));            \
//        len = USART_DMA_RXBUFF_SIZE - DMA_GetCurrDataCounter(this->DMA_Stream); \
//        this->Idle_CallBack(this->rx_data, len);                                \
//        DMA_SetCurrDataCounter(this->DMA_Stream, USART_DMA_RXBUFF_SIZE);        \
//        DMA_Cmd(this->DMA_Stream,ENABLE);                                       \
//    }                                                                           \
//}                                                                               \

/***********************************************************************************
 * @brief 		
 * ex:
 * @par
 * None
 * @retval void None
 **********************************************************************************/
#define  UART_IRQHANDLER(id)                                                    \
void UART##id##_IRQHandler(void)                                                \
{                                                                               \
    usart_para_t * this = &para[id - 1];                                        \
    uint16_t len;                                                               \
                                                                                \
    if(USART_GetITStatus(UART##id, USART_IT_IDLE) != RESET)                     \
    {                                                                           \
        UART##id->SR;                                                           \
        UART##id->DR;                                                           \
        DMA_Cmd(this->DMA_Stream, DISABLE);                                     \
        DMA_ClearFlag(this->DMA_Stream, DMA_Snum(this->DMA_Stream));            \
        len = USART_DMA_RXBUFF_SIZE - DMA_GetCurrDataCounter(this->DMA_Stream); \
        this->Idle_CallBack(this->rx_data, len);                                \
        DMA_SetCurrDataCounter(this->DMA_Stream, USART_DMA_RXBUFF_SIZE);        \
        DMA_Cmd(this->DMA_Stream,ENABLE);                                       \
    }                                                                           \
}                                                                               \


USART_IRQHANDLER(1)
USART_IRQHANDLER(2)
USART_IRQHANDLER(3)
UART_IRQHANDLER(4)
UART_IRQHANDLER(5)
USART_IRQHANDLER(6)


















